package com.richard.base.view

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.os.Handler
import android.util.AttributeSet
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import androidx.core.animation.addListener
import com.lcodecore.tkrefreshlayout.utils.LogUtil
import com.richard.base.R
import okhttp3.internal.toHexString
import java.util.*

/**
 ***************************************
 * 项目名称:Giggle
 * @Author wuzhiguo
 * 邮箱：wuzhiguo@ksjgs.com
 * 创建时间: 2020/9/14     4:00 PM
 * 用途:
 ***************************************
 */

class TransWaveView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : View(context, attrs, defStyle) {

    var bodyWaveList = LinkedList<Int>()

    private var waveList = LinkedList<Int>()

    /**
     * 线间距 px
     */
    var lineSpace: Float = 10f
    /**
     * 线宽 px
     */
    var lineWidth: Float = 20f

    var lineCount: Int = 3

    /**
     * 动画持续时间
     */
    var duration: Long = 200

    /**
     * 百分比， 外部高度默认20dp
     */
    private var percentHeights = intArrayOf(10, 10, 30, 50, 75, 45, 30, 20, 15, 10)

    var initLineHeight: Float = 20f
    /**
     * 线颜色
     */
    private var lineColor: Int = Color.BLUE
    private var paintLine: Paint

    private var valueAnimator = ValueAnimator.ofFloat(0f, 1f)

    private var valueAnimatorOffset: Float = 0f

    private var valHandler = Handler()

    @Volatile
    var isStart: Boolean = false

    /**
     * 跳动模式
     */
    var waveMode: WaveMode = WaveMode.UP_DOWN_IN_TURN

    /**
     * 线条样式
     */
    var lineType: LineType = LineType.BAR_CHART

    /**
     * 显示位置
     */
    var showGravity: Int = Gravity.LEFT or Gravity.BOTTOM

    private var runnable: Runnable? = null


    init {
        attrs?.let {
            val typedArray = context.theme.obtainStyledAttributes(
                attrs,
                R.styleable.VoiceWaveView, 0, 0
            )

            lineWidth = typedArray.getDimension(R.styleable.VoiceWaveView_lineWidth, 20f)
            lineSpace = typedArray.getDimension(R.styleable.VoiceWaveView_lineSpace, 10f)
            duration = typedArray.getInt(R.styleable.VoiceWaveView_duration, 200).toLong()
            showGravity = typedArray.getInt(R.styleable.VoiceWaveView_android_gravity, Gravity.LEFT or Gravity.BOTTOM)
            lineColor = typedArray.getInt(R.styleable.VoiceWaveView_lineColor, Color.BLUE)
            initLineHeight = typedArray.getDimension(R.styleable.VoiceWaveView_initLineHeight, 20f)
            val mode = typedArray.getInt(R.styleable.VoiceWaveView_waveMode, 0)
            when (mode) {
                2 -> waveMode = WaveMode.UP_DOWN_IN_TURN
            }

            val lType = typedArray.getInt(R.styleable.VoiceWaveView_lineType, 0)
            when (lType) {
                0 -> lineType = LineType.BAR_CHART
            }

            typedArray.recycle()
        }

        paintLine = Paint()
        paintLine.isAntiAlias = true
        paintLine.strokeCap = Paint.Cap.ROUND

        if (bodyWaveList.isEmpty()) {
            setLineBody()
        }
    }

    /**
     * 线的高度 0,100 百分数
     */
    fun addBody(num: Int) {
        checkNum(num)
        bodyWaveList.add(num)
    }

    private fun checkNum(num: Int) {
        if (num < 0 || num > 100) {
            throw Exception("num must between 0 and 100")
        }
    }

    /**
     * 开始
     */
    fun start(playDuration: Long) {
        if (isStart) {
            return
        }
        isStart = true
        if (waveMode == WaveMode.UP_DOWN_IN_TURN) {
            valueAnimator.duration = playDuration
//            valueAnimator.repeatMode = ValueAnimator.REVERSE
//            valueAnimator.repeatCount = ValueAnimator.INFINITE
            valueAnimator.addUpdateListener {
                valueAnimatorOffset = it.animatedValue as Float
                invalidate()
            }
            valueAnimator.addListener(onEnd = {
                isStart = false
            })
            valueAnimator.start()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        waveList.clear()
        waveList.addAll(bodyWaveList)
        paintLine.strokeWidth = lineWidth


        canvas.save()
        clipDeepLine(canvas)
        drawLines(canvas, 1f)
        canvas.restore()

        canvas.save()
        drawLines(canvas, 0.3f)
        canvas.restore()
    }

    private fun clipDeepLine(canvas: Canvas) {
        val right = measuredWidth * valueAnimatorOffset
        Log.i("TAG", right.toString())
        val rect = RectF(0f, 0f, right, measuredHeight.toFloat())
        canvas.clipRect(rect)
    }

    private fun drawLines(canvas: Canvas, alpha: Float) {
        val colorStr = lineColor.toHexString()
        val alphaStr = (255 * alpha).toInt().toHexString()
        val finalColorStr = colorStr.replaceRange(0, 2, alphaStr)
        val color = Color.parseColor("#${finalColorStr}")

        for (i in waveList.indices) {
            var startX = 0f
            var startY = 0f
            var endX = 0f
            var endY = 0f

            var offset = 1f

            val lineHeight = waveList[i] / 100f * measuredHeight * offset

            val absoluteGravity = Gravity.getAbsoluteGravity(showGravity, layoutDirection);

            val lineSize = waveList.size
            val allLineWidth = lineSize * (lineSpace + lineWidth)
            if (allLineWidth < measuredWidth) {
                startX = (i * (lineSpace + lineWidth) + lineWidth / 2) + ((measuredWidth - allLineWidth) / 2)
            } else {
                startX = i * (lineSpace + lineWidth) + lineWidth / 2
            }
            endX = startX

            startY = (measuredHeight / 2 - lineHeight / 2).toFloat()
            endY = (measuredHeight / 2 + lineHeight / 2).toFloat()
            paintLine.color = color
            canvas.drawLine(startX, startY, endX, endY, paintLine)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
//        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
//        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val allLineWidth = bodyWaveList.size * (lineSpace + lineWidth)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        if (layoutParams.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            setMeasuredDimension(allLineWidth.toInt(), heightSize)
        }
    }

    /**
     * 停止 onDestroy call
     */
    fun stop() {
        isStart = false
        if (runnable != null) {
            valHandler.removeCallbacks(runnable)
        }
        valueAnimator.cancel()
        valueAnimatorOffset = 0f
        postInvalidate()
    }

    enum class WaveMode {
        UP_DOWN_IN_TURN
    }

    enum class LineType {
        BAR_CHART
    }

    fun setLineColor(color: Int) {
        lineColor = color
        postInvalidate()
    }

    fun setLines(lines: Int) {
        this.lineCount = lines
        setLineBody()
        postInvalidate()
    }


    private fun setLineBody() {
        bodyWaveList.clear()
        for (i in 0..lineCount) {
            var x = i % 10
            addBody(percentHeights[x])
        }
    }
}